import os
## 解决mlflow  保存模型报错 
os.environ['WRAPT_DISABLE_EXTENSIONS'] = 'true'

import mlflow ,json 
import mlflow.keras,mlflow.tensorflow   
from mlflow.tracking import MlflowClient 
import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
from  sklearn.metrics import precision_score,recall_score,f1_score 
import joblib
import tensorflow as tf 
from datetime import datetime, timedelta
import tempfile
import warnings
import pickle 
import matplotlib as mpl
import matplotlib.pyplot as plt
from tensorflow.keras.models import load_model
import  math
import shutil
import time  # 新增导入时间模块 
from hyperopt import fmin, tpe, hp, Trials, STATUS_OK
from utils.lstm_model import *     

warnings.filterwarnings("ignore")
os.environ['TF_DETERMINISTIC_OPS'] = '0'  

# 设置页面
#st.set_page_config(page_title="模型管理", layout="wide")
#st.title("模型管理")

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

mlrun_path = 'mlruns//'
mlartifacts_path ='mlartifacts//' 

mlflow.set_tracking_uri("http://localhost:8095")  
client = MlflowClient(tracking_uri="http://localhost:8095")


def  dl_app():
    # 创建4个tab
    tab1, tab2, tab3,tab4 = st.tabs(["数据上传", "模型训练", "模型管理",'预测']) 
    with tab1:
        #st.header("上传训练数据") 
        st.markdown("""
                    <div style="color:brown; font-size:20px; margin-bottom:20px;">
                    <strong>上传训练数据</strong>
                    </div>
                    """, unsafe_allow_html=True) 
        
        # 数据上传
        train_file = st.file_uploader("上传训练数据 (CSV格式)", type=["csv"])
        val_file = st.file_uploader("上传验证数据 (可选，CSV格式)", type=["csv"])
        
        if train_file is not None:
            # 读取数据
            train_data = pd.read_csv(train_file)
            #st.subheader("训练数据预览")
            st.markdown("""
                <div style="color:brown; font-size:20px; margin-bottom:20px;">
                <strong>训练数据预览</strong>
                </div>
                """, unsafe_allow_html=True) 
            st.dataframe(train_data.head())
            
            # 列选择
            all_columns = train_data.columns.tolist()
            ts_column = st.selectbox("选择时间戳列 (可选)", [None] + all_columns)
            target_column = st.selectbox("选择目标列", all_columns)
            feature_columns = st.multiselect("选择特征列", [col for col in all_columns if col != target_column])

            task_type = st.selectbox("模型类型", ["regression", "binary", "multiclass"], 
                                            format_func=lambda x: {"regression": "回归", "binary": "二分类", "multiclass": "多分类"}[x])
                    
            # 多分类需要指定类别数
            num_classes = None
            if task_type == "multiclass":
                num_classes = st.number_input("类别数量", 2, 100, 2)
            
            # 验证集设置
            if val_file is not None:
                val_data = pd.read_csv(val_file)
                #st.subheader("验证数据预览")
                st.markdown("""
                    <div style="color:brown; font-size:20px; margin-bottom:20px;">
                    <strong>验证数据预览</strong>
                    </div>
                    """, unsafe_allow_html=True) 
                st.dataframe(val_data.head())
                use_split = False
            else:
                use_split = True
                test_size = st.slider("从训练集拆分验证集比例", 0.1, 0.3, 0.2)
            
            # 时间步长设置
            n_steps = st.slider("历史时间步长", 6, 48, 24, step=6)
            
            # 处理数据
            if st.button("预处理数据"):
                if not feature_columns:
                    st.error("请至少选择一个特征列")
                else:
                    with st.spinner("数据预处理中..."):
                        try:
                            val_data_process = pd.read_csv(val_file) if val_file else None
                            data_dict = preprocess_data(
                                train_data=train_data,
                                features_columns=feature_columns,
                                target_column=target_column,
                                val_data=val_data_process,
                                ts_column=ts_column,
                                n_steps=n_steps,
                                test_size=test_size if use_split else 0.2,task_type=task_type 
                            )

                            data_dict['num_classes'] = num_classes 
                            
                            if data_dict:
                                st.session_state.data_dict = data_dict
                                st.session_state.data_dict['n_steps'] = n_steps  # 保存时间步长
                                st.success("数据预处理完成！可以前往模型训练标签页进行训练")
                        except Exception as e:
                            st.error(f"数据预处理失败: {str(e)}")

    with tab2:
        #st.header("模型训练") 
        st.markdown("""
            <div style="color:brown; font-size:20px; margin-bottom:20px;">
            <strong>模型训练</strong>
            </div>
            """, unsafe_allow_html=True) 
        
        if 'data_dict' not in st.session_state or  st.session_state['data_dict'] is None or 'n_steps' not in st.session_state['data_dict']  or st.session_state['data_dict']['n_steps'] is None  :

            st.warning("请先在数据上传标签页加载并预处理数据")
        else:
            print('data_dict',st.session_state['data_dict']) 
            # 模型参数设置区域
            with st.expander("模型参数设置", expanded=True):
                col1, col2 = st.columns(2)
                
                with col1:
                    # 模型基本信息
                    exp_name = st.text_input("实验名称", "lstm")  
                    model_name = st.text_input("模型名称", "lstm_run")  
                    
                    num_classes  = st.session_state.data_dict['num_classes']  
                    
                    # Hyperopt选项
                    use_hyperopt = st.checkbox("使用Hyperopt参数搜索", value=False) 

                    try: 
                        mlflow.create_experiment(exp_name) 
                    except:
                        pass  

                    mlflow.set_experiment(exp_name)   
                
                with col2:
                    # 时间步长（从数据预处理获取）
                    st.text(f"历史时间步长: {st.session_state.data_dict['n_steps']}")
                    n_steps = st.session_state.data_dict['n_steps']
                    
                    # 特征和目标列信息
                    st.text(f"特征列数量: {len(st.session_state.data_dict['feature_names'])}")
                    st.text(f"目标列: {st.session_state.data_dict['target_column']}")
            
            # 超参数搜索配置
            if use_hyperopt:
                #st.subheader("Hyperopt参数搜索配置")
                st.markdown("""
                    <div style="color:brown; font-size:20px; margin-bottom:20px;">
                    <strong>Hyperopt参数搜索配置</strong>
                    </div>
                    """, unsafe_allow_html=True)
                with st.form("hyperopt_form"):
                    col1, col2 = st.columns(2)
                    
                    with col1:
                        max_evals = st.slider("最大尝试次数", 1, 200, 50)
                        
                        # LSTM层数设置（1-7层）
                        num_layers = st.slider("LSTM层数", 1, 7, 3)
                        
                        # 每层LSTM单元数范围
                        lstm_units_layers = []
                        for i in range(num_layers):
                            #st.subheader(f"第{i+1}层LSTM单元数范围")
                            st.markdown(f"""
                                <div style="color:black; font-size:15px; margin-bottom:20px;">
                                <strong>第{i+1}层LSTM单元数范围</strong>
                                </div>
                                """, unsafe_allow_html=True)
                            
                            min_u = st.slider(f"最小单元数", 16, 256, 32, step=16, key=f"min_{i}")
                            max_u = st.slider(f"最大单元数", min_u, 256, min(min_u+32, 256), step=16, key=f"max_{i}")
                            lstm_units_layers.append((min_u, max_u, 16))
                    
                    with col2:
                        # 其他参数范围
                        dropout_min = st.slider("Dropout率最小值", 0.0001, 0.5, 0.1, step=0.05)
                        dropout_max = st.slider("Dropout率最大值", 0.0001, 0.5, 0.3, step=0.05)
                        
                        learning_rate_min = st.slider("学习率最小值", 0.0001, 0.01, 0.0001, step=0.0001, format="%.4f")
                        learning_rate_max = st.slider("学习率最大值", 0.0001, 0.01, 0.001, step=0.0001, format="%.4f")
                        
                        epochs_min = st.slider("训练轮次最小值", 5, 200, 50, step=5)
                        epochs_max = st.slider("训练轮次最大值", epochs_min, 500, 200, step=5)
                        
                        patience_min = st.slider("早停耐心值最小值", 5, 50, 10, step=5)
                        patience_max = st.slider("早停耐心值最大值", patience_min, 50, 30, step=5)
                        
                        # 优化器和批量大小选项
                        optimizers = st.multiselect("优化器选项", ["Adam", "RMSprop", "SGD"], default=["Adam"])
                        batch_sizes = st.multiselect("批量大小选项", [16, 32, 64, 128], default=[32, 64])
                    
                    
                    hyperopt_params = {
                        'max_evals': max_evals,
                        'lstm_units_layers': lstm_units_layers,
                        'dropout_min': dropout_min,
                        'dropout_max': dropout_max,
                        'learning_rate_min': learning_rate_min,
                        'learning_rate_max': learning_rate_max,
                        'epochs_min': epochs_min,
                        'epochs_max': epochs_max,
                        'patience_min': patience_min,
                        'patience_max': patience_max,
                        'optimizers': optimizers,
                        'batch_sizes': batch_sizes
                    }

                    hyperopt_submit = st.form_submit_button("确认超参数配置")  
                if hyperopt_submit:
                    st.success("超参数搜索配置已确认") 
            
            # 固定参数配置 
            else:
                #st.subheader("模型固定参数配置")
                st.markdown("""
                    <div style="color:brown; font-size:20px; margin-bottom:20px;">
                    <strong>模型固定参数配置</strong>
                    </div>
                    """, unsafe_allow_html=True)
                
                with st.form("fixed_params_form"):
                    col1, col2 = st.columns(2)
                    
                    with col1:
                        # LSTM层数和单元数（1-7层）
                        num_layers = st.slider("LSTM层数", 1, 7, 3)
                        lstm_units = []
                        for i in range(num_layers):
                            units = st.number_input(f"第{i+1}层LSTM单元数", 16, 256, 64, step=16)
                            lstm_units.append(units)
                        
                        dropout_rate = st.slider("Dropout率", 0.0, 0.5, 0.2, 0.05)
                    
                    with col2:
                        optimizer_name = st.selectbox("优化器", ["Adam", "RMSprop", "SGD"], index=0)
                        learning_rate = st.slider("学习率", 0.0001, 0.01, 0.0005, 0.0001, format="%.4f")
                        epochs = st.number_input("最大训练轮次", 5, 1000, 100)
                        batch_size = st.selectbox("批量大小", [16, 32, 64, 128], index=1)
                        patience = st.slider("早停耐心值", 3, 50, 30)
                    
                    fixed_submit = st.form_submit_button("确认固定参数配置") 
                
                if fixed_submit:
                    st.success("固定参数配置已确认")
            
            # 训练模型按钮
            if st.button("开始训练模型"):
                with st.spinner("模型训练中..."):
                    try:
                        if use_hyperopt:
                            print(hyperopt_params) 
                            if not hyperopt_params:
                                st.error("请先确认超参数配置")
                                st.stop()
                            
                            # 开始超参数搜索训练
                            with mlflow.start_run(run_name=f"{model_name}_hyperopt_search",nested=True):
                                mlflow.log_param("hyperopt_max_evals", hyperopt_params['max_evals'])
                                mlflow.log_param("search_space", str(hyperopt_params))
                                mlflow.log_param("task_type", task_type)
                                if task_type == "multiclass":
                                    mlflow.log_param("num_classes", num_classes)
                                
                                model, history = train_universal_model(
                                    data_dict=st.session_state.data_dict,
                                    experiment_name=exp_name,
                                    task_type=task_type,
                                    num_classes=num_classes,
                                    model_name=model_name,
                                    use_hyperopt=True,
                                    hyperopt_params=hyperopt_params
                                )
                        else:
                            # 固定参数训练
                            model, history = train_universal_model(
                                data_dict=st.session_state.data_dict,
                                experiment_name=exp_name,
                                task_type=task_type,
                                num_classes=num_classes,
                                epochs=epochs,
                                lstm_units=lstm_units,
                                dropout_rate=dropout_rate,
                                batch_size=batch_size,
                                patience=patience,
                                model_name=model_name,
                                optimizer_name=optimizer_name,
                                learning_rate=learning_rate,
                                use_hyperopt=False
                            )
                        
                        if model is None:
                            st.error("模型训练失败")
                            st.stop()
                        
                        # 评估模型
                        train_pred = model.predict(st.session_state.data_dict['X_train'], verbose=0)
                        val_pred = model.predict(st.session_state.data_dict['X_val'], verbose=0)
                        
                        # 反归一化
                        # 根据任务类型处理反归一化
                        task_type = st.session_state.data_dict['task_type'] 
                        print('now  task_type:',task_type) 
                        print('here2 ~') 
                        # 处理训练集真实值和预测值
                        if task_type == "regression" and 'target_scaler' in st.session_state.data_dict:
                            y_train_true = st.session_state.data_dict['target_scaler'].inverse_transform(
                                st.session_state.data_dict['y_train'].reshape(-1, 1)).flatten()
                            y_train_pred = st.session_state.data_dict['target_scaler'].inverse_transform(
                                train_pred.reshape(-1, 1)).flatten()
                        
                        elif task_type == "binary":
                            # 二分类任务：返回概率值(如需类别可自行添加阈值判断) 
                            y_train_true = st.session_state.data_dict['y_train'].flatten()
                            y_train_pred = train_pred.flatten()  

                        else:  # multiclass

                            # 多分类任务：返回预测类别(如需概率可返回y_pred_scaled)
                            y_train_true = st.session_state.data_dict['y_train'].flatten() 
                            y_train_pred = np.argmax(train_pred, axis=1) 
                            # 如果有标签编码器，转换为原始标签
                            if 'label_encoder' in st.session_state.data_dict:
                                y_train_pred = st.session_state.data_dict['label_encoder'].inverse_transform(y_train_pred)


                        # 处理验证集真实值和预测值
                        if task_type == "regression" and 'target_scaler' in st.session_state.data_dict:
                            y_val_true = st.session_state.data_dict['target_scaler'].inverse_transform(
                                st.session_state.data_dict['y_val'].reshape(-1, 1)).flatten()
                            y_val_pred = st.session_state.data_dict['target_scaler'].inverse_transform(
                                val_pred.reshape(-1, 1)).flatten()
                        elif task_type == "binary":
                            # 二分类任务：返回概率值(如需类别可自行添加阈值判断) 
                            y_val_true = st.session_state.data_dict['y_val'].flatten()
                            y_val_pred = val_pred.flatten()  

                        else:  # multiclass
                            # 多分类任务：返回预测类别(如需概率可返回y_pred_scaled)
                            y_val_true = st.session_state.data_dict['y_val'].flatten() 
                            y_val_pred = np.argmax(val_pred, axis=1)
                            # 如果有标签编码器，转换为原始标签
                            if 'label_encoder' in st.session_state.data_dict:
                                y_val_pred = st.session_state.data_dict['label_encoder'].inverse_transform(y_val_pred)
                        
                        # 计算指标
                        
                        def calculate_metrics(y_true, y_pred, task_type):
                            if task_type == "regression":
                                return {
                                    'MAE': mean_absolute_error(y_true, y_pred),
                                    'RMSE': np.sqrt(mean_squared_error(y_true, y_pred)),
                                    'R2': r2_score(y_true, y_pred)
                                }
                            elif task_type == "binary":
                                # 二分类指标
                                return {
                                    'Accuracy': accuracy_score(y_true, y_pred.round()),
                                    'Precision': precision_score(y_true, y_pred.round()),
                                    'Recall': recall_score(y_true, y_pred.round()),
                                    'F1': f1_score(y_true, y_pred.round())
                                }
                            elif task_type == "multiclass":
                                # 多分类指标
                                return {
                                    'Accuracy': accuracy_score(y_true, y_pred),
                                    'Precision': precision_score(y_true, y_pred, average='macro'),
                                    'Recall': recall_score(y_true, y_pred, average='macro'),
                                    'F1': f1_score(y_true, y_pred, average='macro')
                                }
                        
                        train_metrics = calculate_metrics(y_train_true, y_train_pred, task_type)
                        val_metrics = calculate_metrics(y_val_true, y_val_pred, task_type)

                        train_metrics = calculate_metrics(y_train_true, y_train_pred, task_type)
                        val_metrics = calculate_metrics(y_val_true, y_val_pred, task_type)
                        

                        # 保存结果
                        st.session_state.model = model
                        st.session_state.train_metrics = train_metrics
                        st.session_state.val_metrics = val_metrics
                        if history is not None:
                            st.session_state.history = history
                        
                        # 显示结果
                        st.success("模型训练完成!")
                        
                        col1, col2 = st.columns(2)
                        with col1:
                            #st.subheader("训练集表现")
                            st.markdown("""
                                <div style="color:brown; font-size:20px; margin-bottom:20px;">
                                <strong>训练集表现</strong>
                                </div>
                                """, unsafe_allow_html=True) 
                            
                            for k in train_metrics.keys():
                                st.metric(k, f"{train_metrics[k]:.2f}")

                        
                        with col2:
                            #st.subheader("验证集表现")
                            st.markdown("""
                                <div style="color:brown; font-size:20px; margin-bottom:20px;">
                                <strong>验证集表现</strong>
                                </div>
                                """, unsafe_allow_html=True) 

                            for k in val_metrics.keys():
                                st.metric(k, f"{val_metrics[k]:.2f}")
                        
                        # 绘制训练曲线
                        if 'history' in st.session_state:
                            fig, ax = plt.subplots(figsize=(12, 6))
                            plt.rcParams.update({'font.size': 8})
                            ax.plot(st.session_state.history.history['loss'], label='训练损失')
                            ax.plot(st.session_state.history.history['val_loss'], label='验证损失')
                            ax.set_title('训练历史')
                            ax.set_xlabel('Epoch')
                            ax.set_ylabel('Loss')
                            ax.legend()
                            st.pyplot(fig)
                        
                        # 绘制预测对比
                        fig, ax = plt.subplots(figsize=(12, 6))
                        plt.rcParams.update({'font.size': 8}) 
                        ax.plot(y_val_true[:100], label='实际值', alpha=0.7)
                        ax.plot(y_val_pred[:100], label='预测值', alpha=0.7)
                        ax.set_title('验证集预测对比 (前100个样本)')
                        ax.legend()
                        st.pyplot(fig)
                        
                    except Exception as e:
                        st.error(f"训练失败: {str(e)}")  

    with tab3:
        external_website_url = "http://localhost:8095"  

        # 显示外部网站的内容
        st.markdown(f'<iframe src="{external_website_url}" width="100%" height="800"></iframe>', unsafe_allow_html=True)


    with tab4:
        # 设置页面标题
        #st.title("模型预测")
        st.markdown("""
            <div style="color:brown; font-size:20px; margin-bottom:20px;">
            <strong>模型预测</strong>
            </div>
            """, unsafe_allow_html=True) 
        
        # 1. 上传测试数据集
        #st.subheader("1. 上传测试数据集")
        st.markdown("""
            <div style="color:black; font-size:18px; margin-bottom:20px;">
            <strong>1. 上传测试数据集</strong>
            </div>
            """, unsafe_allow_html=True) 
        test_file = st.file_uploader("请上传CSV格式的测试数据", type=["csv"])
        
        if test_file is not None:
            # 读取测试数据
            test_data = pd.read_csv(test_file)
            st.success("测试数据上传成功！")
            st.dataframe(test_data.head())
            
            # 2. 展示注册模型列表
            #st.subheader("2. 选择预测模型")
            st.markdown("""
            <div style="color:black; font-size:18px; margin-bottom:20px;">
            <strong>2. 选择预测模型</strong>
            </div>
            """, unsafe_allow_html=True) 
            model_df = get_rg_models()
            
            if not model_df.empty:
                st.dataframe(model_df)
                
                # 选择模型
                model_options = [f"{row['模型名称']} (版本: {row['version_id']}, val_loss: {row['val_loss']})" 
                            for _, row in model_df.iterrows()]
                selected_model = st.selectbox("选择要使用的模型", model_options)
                
                # 解析选择的模型信息
                selected_model_name = selected_model.split(" (版本: ")[0]
                selected_version = selected_model.split(" (版本: ")[1].split(",")[0]
                
                # 3. 预测参数设置
                #st.subheader("3. 预测参数")
                st.markdown("""
                    <div style="color:black; font-size:18px; margin-bottom:20px;">
                    <strong>3. 预测参数</strong> 
                    </div>
                    """, unsafe_allow_html=True) 
                # 获取数据字典信息（假设从模型元数据中获取，这里简化处理）
                # 实际应用中可能需要从模型注册中加载相关元数据
                if st.button("开始预测"):
                    with st.spinner("正在加载模型并进行预测..."):
                        try:
                            # 加载模型

                            run_id =  model_df[(model_df['version_id'] == selected_version)& (model_df['模型名称'] == selected_model_name)]['run_id'].values[0]
                            #mlartifacts_path ='mlruns//'  


                            exp_id = mlflow.get_run(run_id).info.experiment_id    
                            run_name = model_df[(model_df['version_id'] == selected_version)& (model_df['模型名称'] == selected_model_name)]['run_name'].values[0]
                            artifact_path = f"{mlartifacts_path}/{exp_id}//{run_id}//artifacts"  

                            feature_scaler_path = artifact_path + '/feature_scaler/feature_scaler.pkl'
                            #target_scaler_path = artifact_path + '/target_scaler/target_scaler.pkl'
                            model_path = artifact_path + '/model/'+run_name+'.h5' 

                            import joblib
                            from tensorflow.keras.models import load_model 
                            with open(feature_scaler_path, 'rb') as f:
                                feature_scaler = joblib.load(f)  
                                
                            #with open(target_scaler_path, 'rb') as f:
                            #    target_scaler = joblib.load(f)  
                                
                            model = load_model(model_path)  

                            run = mlflow.get_run(run_id)  
                            run_params = run.data.params


                            # 
                            data_dict = {
                                'feature_names': json.loads(run_params['feature_names']),  # 
                                'target_column': run_params['target_column'],  # 需根据实际情况调整
                                'n_steps': int(run_params['n_steps']),  # 需从模型元数据中获取
                                'feature_scaler': feature_scaler,
                                'task_type': run_params['task_type']  # 实际应从模型元数据中获取
                            }
                            
                            task_type = run_params['task_type'] 
                            # 检查是否有标签编码器（分类任务）
                            if task_type == 'multiclass' : 
                                label_encoder_artifacts = artifact_path + '/label_encoder/label_encoder.pkl' 
                                label_encoder = joblib.load(label_encoder_artifacts)  
                                data_dict['label_encoder'] = label_encoder
                            
                            if  task_type =='regression' : 
                                target_scaler_artifacts = artifact_path + '/target_scaler/target_scaler.pkl' 
                                target_scaler = joblib.load(target_scaler_artifacts)  
                                data_dict['target_scaler'] = target_scaler
                            
                            # 执行预测
                            predict_result = predict_values(model, test_data, data_dict) 
                            
                            
                            if predict_result:
                                st.success("预测完成！")
                                
                                # 4. 展示预测结果
                                #st.subheader("4. 预测结果")
                                st.markdown("""
                                    <div style="color:black; font-size:18px; margin-bottom:20px;">
                                    <strong>4. 预测结果</strong> 
                                    </div>
                                    """, unsafe_allow_html=True) 
                                result_df = pd.DataFrame({
                                    '索引': predict_result['pred_indices'],
                                    '预测值': predict_result['y_pred']
                                })
                                if  data_dict['target_column'] in test_data:
                                    result_df['实际值'] = test_data.loc[predict_result['pred_indices'], data_dict['target_column']].values 

                                st.dataframe(result_df) 
                                
                                # 5. 计算并展示评估指标
                                st.markdown("""
                                    <div style="color:black; font-size:18px; margin-bottom:20px;">
                                    <strong>5. 预测评估指标</strong> 
                                    </div>
                                    """, unsafe_allow_html=True) 
                                metrics = evaluate_test_set(predict_result, test_data, data_dict)
                                
                                if metrics:
                                    # 以卡片形式展示关键指标
                                    cols = st.columns(3)
                                    if metrics['task_type'] == 'regression':
                                        cols[0].metric("MAE", f"{metrics['mae']:.4f}")
                                        cols[1].metric("RMSE", f"{metrics['rmse']:.4f}")
                                        cols[2].metric("R2", f"{metrics['r2']:.4f}")
                                        
                                        # 展示详细指标
                                        st.write("详细指标：")
                                        st.json(metrics)
                                    elif metrics['task_type'] == 'binary':
                                        cols[0].metric("准确率", f"{metrics['accuracy']:.4f}")
                                        cols[1].metric("精确率", f"{metrics['precision']:.4f}")
                                        cols[2].metric("召回率", f"{metrics['recall']:.4f}")
                                        
                                        # 展示详细指标
                                        st.write("详细指标：")
                                        st.json(metrics)
                                    elif metrics['task_type'] == 'multiclass':
                                        cols[0].metric("准确率", f"{metrics['accuracy']:.4f}")
                                        cols[1].metric("宏平均F1", f"{metrics['macro_f1']:.4f}")
                                        cols[2].metric("加权平均F1", f"{metrics['weighted_f1']:.4f}")
                                        
                                        # 展示详细指标
                                        st.write("详细指标：")
                                        st.json(metrics)
                        except Exception as e:
                            st.error(f"预测过程出错: {str(e)}")
            else:
                st.warning("没有找到已注册的模型，请先训练并注册模型")
        else:
            st.info("请先上传测试数据集")